#! /usr/bin/env python 
import sys
import re
import urllib
import urllib2
import urlparse
import optparse
from BeautifulSoup import BeautifulSoup

from modules.utils import *

def build_search_result_url(name, artist=None):
    """
    build search result url for wo99.com

    example:
        http://ok.wo99.com/search_pjz.php?txt=%BE%D5%BB%A8%CC%A8&in=songname&by=banzou&page=1&submit=%CB%D1%CB%F7
    """
    base_url = 'http://ok.wo99.com/search_pjz.php'
    if name:
        word = name
        in_val = 'songname'
    elif artist:
        word = artist
        in_val = ''
    else:
        return None

    try:
       encoding = guess_encoding(word)
    except:
        print "I can not guess the encoding of your input"
        raise

    if encoding!='gbk':
        gb_word = convert_string_encoding(word, encoding, 'gbk')
    else:
        gb_word = word

    params_tuples = (
              ('txt',gb_word),
              ('in',in_val),
              ('by','banzou'),
              ('page','1'),
              ('submit','\xcb\xd1\xcb\xf7'),
             )
    params = urllib.urlencode(params_tuples)
    if params:
        url = base_url + '?' + params
    else:
        url = base_url
    return url

def download_song(url, dl, song_page, options):
    song_page.reset()
    result, reason = song_page.open(url)
    selected_songs = song_page.select_song()
    if result:
        if selected_songs:
            song_base_name = selected_songs[0].name
            dl_page_url = selected_songs[0].url

            if options.song:
                dl_song_page = SongDownloadPage()
                song_url = dl_song_page.get_download_link(dl_page_url)
                if song_url:
                    song_name = song_base_name + '.' + song_url[-3:].lower()
                    print "Dowload song %s" % song_name
                    dl.download(song_name, song_url)
            return True
        else:
            print "Don't find any matched song."
            return False
    else:
        print "Failed to download song for reason(%s)"%reason
        return False

class SongDownloadPage:
    def get_download_link(self, dl_page_url):
        if not dl_page_url:
            return None
        req = urllib2.Request(dl_page_url)
        opener = urllib2.build_opener(req)
        res = opener.open(req)
        cookie = res.info()['Set-Cookie']
        dl_url_pat = re.compile('download=([^;]+);')
        groups = dl_url_pat.search(cookie).groups()

        if len(groups)==1:
            link = encode_url(groups[0])
            return link
        else:
            return None

class SongPage:
    def __init__(self):
        self.base_url = 'http://ok.wo99.com'
        self.reset()
    def reset(self):
        self.header = []
        self.song_info_list = []

    def open(self, url):
        """
        I will open given url for download song 

        If Success, I will return True and a empty string
        otherwise,  I will return False and the reason string
        """
        soup = get_soup(url)
        tbodies = soup.findAll('tbody')

        if len(tbodies)!=3:
            # GOTCHA: 
            #  maybe the given url is not right
            raise WebPageLayoutChange()

        tbody = tbodies[1]
        trs = tbody.findAll('tr')
        if len(trs)==0:
            raise WebPageLayoutChange()
        elif len(trs)==1:
            return False, 'No song found.'

        #self.header = self._build_header(trs[0])
        song_info_entries = trs[1:]
        for song_info in song_info_entries:
            self.song_info_list.append(self._build_song_info(song_info))
        return True, ''

    def select_song(self, minsize=1.2):
        result = [song_info for song_info in self.song_info_list
                  if song_info.size>minsize
                  and song_info.url!='' ]
        def cmp(x, y):
            if x.speed>y.speed:
                return 1
            elif x.speed<y.speed:
                return -1
            else:
                return 0
        if result:
            result.sort(cmp)
        return result

    def _get_url(self, onclick_cmd):
        start = onclick_cmd.find('/')
        if start==-1:
            return None
        end = onclick_cmd.find('\'', start)
        if end==-1:
            return None
        url = self.base_url + onclick_cmd[start:end]
        return encode_url(url)

    def _build_song_info(self, song_info_html):
        song_info = SongInfo()
        if not song_info_html:
            return song_info

        items = song_info_html.findAll('td')
        song_info.number = int(items[0].string)

        try:
            song_info.name = items[1].a.string.replace(' ', '_')
        except:
            pass

        song_info.url = self._get_url(items[1].a['onclick'])

        try:
            song_info.artist = items[2].a.string
        except:
            pass

        if hasattr(items[7], 'a') and hasattr(items[7].a, 'href'):
            song_info.lyric_url = encode_url(self.base_url+'/'+items[7].a['href'])

        try:
            song_info.size = float(items[5].string[:-1])
        except:
            #ignore invalid format of size
            pass

        song_info.speed = int(items[6].string)

        return song_info

if __name__ == '__main__':
    parser = optparse.OptionParser(usage="%prog [OPTION]...",
                                   version="%prog1.0")
    parser.add_option('-n', '--name', dest='name',
                      help='song\'s name to search')
    parser.add_option('-a', '--artist', dest='artist',
                      help='artist\'s name to search')
    parser.add_option('-t', '--dry-run', dest='dry_run',
                      action="store_true", default=False,
                      help='do not actually download files')
    parser.add_option('-s', '--nosong', dest='song',
                      action="store_false", default=True,
                      help='not download song, default download')
    options, args = parser.parse_args()

    dl = Downloader(output_indent=' '*4, dry_run_mode=options.dry_run)
    song_page = SongPage()

    if options.artist or options.name:
        url = build_search_result_url(name=options.name, artist=options.artist)
        download_song(url, dl, song_page, options)
